package com.lsh.payment.core.service.dmallpay.impl;

import com.alibaba.fastjson.JSONObject;
import com.lsh.payment.api.model.basevo.ExceptionStatus;
import com.lsh.payment.api.model.dmallpay.DMallNotifyRequest;
import com.lsh.payment.api.model.dmallpay.DMallNotifyRequestParam;
import com.lsh.payment.core.exception.BusinessException;
import com.lsh.payment.core.model.payenum.OperateStatus;
import com.lsh.payment.core.model.payenum.PayStatus;
import com.lsh.payment.core.model.payment.PayDeal;
import com.lsh.payment.core.service.dmallpay.IDMallNotifyService;
import com.lsh.payment.core.service.paylog.PayLogService;
import com.lsh.payment.core.service.payment.impl.PayBaseService;
import com.lsh.payment.core.service.payment.impl.PayDealService;
import com.lsh.payment.core.strategy.config.DMallPayConfig;
import com.lsh.payment.core.util.DateUtil;
import com.lsh.payment.core.util.pay.dmallpay.DMallSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Set;

/**
 * Project Name: lsh-payment
 * Created by panxudong
 * Date: 17/11/14
 * 北京链商电子商务有限公司
 * Package com.lsh.payment.core.service.dmallpay.impl
 * desc:
 */
@Service
@Transactional(readOnly = true)
public class DMallNotifyServiceImpl implements IDMallNotifyService {

    private Logger logger = LoggerFactory.getLogger(DMallNotifyServiceImpl.class);

    @Autowired
    private PayDealService payDealService;

    @Autowired
    private PayBaseService payBaseService;

    @Autowired
    private PayLogService payLogService;

    private static void valid(Object obj) throws BusinessException {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        Validator validator = factory.getValidator();
        Set<ConstraintViolation<Object>> cvs = validator.validate(obj);
        if (CollectionUtils.isEmpty(cvs)) {
            return;
        }
        StringBuilder builder = new StringBuilder(ExceptionStatus.E1002001.getMessage());
        for (ConstraintViolation cv : cvs) {
            builder.append("[").append(cv.getPropertyPath().toString()).append("] ").append(cv.getMessage()).append("\n");
        }
        builder.deleteCharAt(builder.length() - 1);
        String message = builder.toString();
        throw new BusinessException(ExceptionStatus.E1002001.getCode(), message);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean dMallNotify(DMallNotifyRequest notifyRequest) throws Exception {
        //TODO:目前不判断回调支付状态,只有成功才回调,以后需沟通加上

        //验证请求参数
        valid(notifyRequest);

        DMallNotifyRequestParam request = notifyRequest.getParam();

        //验签
        if (!DMallSignature.checkSign(request, DMallPayConfig.NOTIFY_KEY, notifyRequest.getSign())) {
            logger.error("验签失败");
            throw new BusinessException(ExceptionStatus.E2001017.getCode(),
                    ExceptionStatus.E2001017.getMessage());
        }

        //查询payDeal
        String paymentNo = request.getThirdOrderId();
        PayDeal payDeal = payDealService.queryPayDealByPayPaymentNo(paymentNo);
        if (payDeal == null) {
            logger.error("没有查到记录:" + paymentNo);
            throw new BusinessException(ExceptionStatus.E2001006.getCode(), ExceptionStatus.E2001006.getMessage());
        }

        //幂等保持 判断payDeal的状态,如果已为支付成功,则直接返回,如果没有则置为成功
        if (payDeal.getPayStatus() == PayStatus.PAY_SUCCESS.getValue()) {
//            this.insertLog(payDeal, notifyRequest, BusinessConstant.OPERATE_SUCCESS, BusinessConstant.OPERATE_SUCCESS_STRING);

            logger.info("支付结果重复回调");
            return true;
        }

        //校验金额
        BigDecimal actualAmount = new BigDecimal(request.getActualAmount()).divide(new BigDecimal(100));
        if (actualAmount.doubleValue() != payDeal.getRequestAmount().doubleValue()) {
            logger.error("回调原始金额与请求金额不符");
            throw new BusinessException(ExceptionStatus.E2001016.getCode(), ExceptionStatus.E2001016.getMessage());
        }

        //更新payDeal
        PayDeal payDealUpdate = new PayDeal();
        payDealUpdate.setPayId(payDeal.getPayId());
        payDealUpdate.setPayStatus(PayStatus.PAY_SUCCESS.getValue());
        payDealUpdate.setOperateStatus(OperateStatus.PAYMENT_CALLBACK.getCode());
        payDealUpdate.setChannelTransaction(request.getOrderId());
        payDealUpdate.setPayTime(DateUtil.parsePayDate(request.getPaymentTime()));
        payDealUpdate.setReceiveAmount(actualAmount);
        payDealUpdate.setDoneTime(new Date());

        String ext = payDeal.getExt();
        JSONObject extObject;
        if (StringUtils.hasText(ext)) {
            extObject = JSONObject.parseObject(ext);
        } else {
            extObject = new JSONObject();
        }
        extObject.put("paymentType", request.getPaymentType());
        extObject.put("cartId", request.getCartId());
        extObject.put("realPayAmount", new BigDecimal(request.getRealPayAmount()).divide(new BigDecimal(100)));
        extObject.put("payDiscountAmount", new BigDecimal(request.getPayDiscountAmount()).divide(new BigDecimal(100)));
        payDealUpdate.setExt(extObject.toJSONString());

        payBaseService.updPayDeal(payDealUpdate, payDeal);

        //插入日志表
//        this.insertLog(payDeal, notifyRequest, BusinessConstant.OPERATE_SUCCESS, BusinessConstant.OPERATE_SUCCESS_STRING);

        return true;
    }

//    private void insertLog(PayDeal payDeal, DMallNotifyRequest notifyRequest,
//                           Integer logStatus, String backResult) {
//
//        payLogService.insertLog(payDeal.getPayId(), payDeal.getPayPaymentNo(),
//                payDeal.getTradeId(), BusinessConstant.LOG_PAY_TYPE_PAY_NOTIFY,
//                logStatus, JSON.toJSONString(notifyRequest), backResult);
//    }

}
